{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**问题：**\n",
    "假设你正在为一个电影推荐系统设计一个简单的KNN算法。我们有以下一些用户的电影评分数据，数据由两个特征组成：用户对电影A和电影B的评分，分别在1-5之间。用户的标签（电影类型偏好）是动作片（标签0）或者是喜剧片（标签1）。我们有一个新用户，他给电影A评分为3，电影B评分为4。请问这个用户可能偏好哪种类型的电影？\n",
    "\n",
    "**数据：**\n",
    "\n",
    "| 用户   | 电影A评分 | 电影B评分 | 偏好类型 |\n",
    "| ------ | --------- | --------- | -------- |\n",
    "| 用户1  | 5         | 1         | 动作片   |\n",
    "| 用户2  | 4         | 2         | 动作片   |\n",
    "| 用户3  | 2         | 5         | 喜剧片   |\n",
    "| 用户4  | 1         | 4         | 喜剧片   |\n",
    "| 用户5  | 3         | 2         | 动作片   |\n",
    "| 用户6  | 2         | 5         | 喜剧片   |\n",
    "\n",
    "你需要做以下步骤：\n",
    "1. 构造数据\n",
    "2. 创建KNN模型\n",
    "3. 使用数据训练模型\n",
    "4. 预测新用户的喜好"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 0. 引入核心包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. X, y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造特征数据：用户对电影A和电影B的评分\n",
    "X = np.array([\n",
    "    [5, 1],  # 用户1\n",
    "    [4, 2],  # 用户2\n",
    "    [2, 5],  # 用户3\n",
    "    [1, 4],  # 用户4\n",
    "    [3, 2],  # 用户5\n",
    "    [2, 5]   # 用户6\n",
    "])\n",
    "\n",
    "# 构造标签数据：0表示动作片，1表示喜剧片\n",
    "y = np.array([0, 0, 1, 1, 0, 1]) "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 创建 KNN 模型\n",
    "k = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn = KNeighborsClassifier(n_neighbors=1) "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-2 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: #000;\n",
       "  --sklearn-color-text-muted: #666;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-2 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-2 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-2 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: flex;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "  align-items: start;\n",
       "  justify-content: space-between;\n",
       "  gap: 0.5em;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 label.sk-toggleable__label .caption {\n",
       "  font-size: 0.6rem;\n",
       "  font-weight: lighter;\n",
       "  color: var(--sklearn-color-text-muted);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-2 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-2 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-2 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-2 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-2 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-2 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 0.5em;\n",
       "  text-align: center;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-2 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-2 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>KNeighborsClassifier(n_neighbors=1)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" checked><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>KNeighborsClassifier</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.neighbors.KNeighborsClassifier.html\">?<span>Documentation for KNeighborsClassifier</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\"><pre>KNeighborsClassifier(n_neighbors=1)</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "KNeighborsClassifier(n_neighbors=1)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn.fit(X, y)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 用模型推理(预测)用户的喜好"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "新用户可能偏好的电影类型：喜剧片\n"
     ]
    }
   ],
   "source": [
    "new_user = np.array([[3, 4]])\n",
    "prediction = knn.predict(new_user)\n",
    "print(f\"新用户可能偏好的电影类型：{'喜剧片' if prediction[0] == 1 else '动作片'}\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 数据可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 26032 (\\N{CJK UNIFIED IDEOGRAPH-65B0}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 29992 (\\N{CJK UNIFIED IDEOGRAPH-7528}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 25143 (\\N{CJK UNIFIED IDEOGRAPH-6237}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 26368 (\\N{CJK UNIFIED IDEOGRAPH-6700}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 36817 (\\N{CJK UNIFIED IDEOGRAPH-8FD1}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 37051 (\\N{CJK UNIFIED IDEOGRAPH-90BB}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 36830 (\\N{CJK UNIFIED IDEOGRAPH-8FDE}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 25509 (\\N{CJK UNIFIED IDEOGRAPH-63A5}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 21160 (\\N{CJK UNIFIED IDEOGRAPH-52A8}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 20316 (\\N{CJK UNIFIED IDEOGRAPH-4F5C}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n",
      "/home/yuyuyu/.local/lib/python3.10/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 29255 (\\N{CJK UNIFIED IDEOGRAPH-7247}) missing from font(s) DejaVu Sans.\n",
      "  fig.canvas.print_figure(bytes_io, **kw)\n"
     ]
    },
    {
     "data": {
      "image/png": "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Z4o++eQTXL58GQ0aNECTJk10RoMfP37cZMERERERWYrRRVHJU6uJiIiI7InRRdGcOXPMEQcRERGRVRk9poiIiIjIHhl0pqhOnTq4cOEC6tWrh9q1a5f7bKI7d+6YLDgiIiIiSzGoKIqLi4OHh4fm96o8sJGIiIioOjKoKBo1apTm99GjR5srFiIiIiKrMXpMkYODA27evKmz/Pbt23BwcDBJUERERESWZnRRJITQu1wul8PZ2bnKARERERFZg8G35H/++ecAAIlEgpUrV8Ld3V2zTqlUYt++fQgICDB9hEREREQWYHBRVDLnmBACX375pdalMmdnZzRp0gRffvml6SMkIiIisgCDi6IrV64AAHr16oUNGzagdu3aZguKiIiIyNKMfqL1b7/9Zo44iIiIiKzK6KIIAK5du4bNmzcjPT0dxcXFWus+/fRTkwRGREREZElGF0W7d+/GwIED8dhjj+Gvv/5C27ZtkZaWBiEEQkJCzBEjERERkdkZfUv+jBkzMGXKFJw6dQouLi746aefkJGRgbCwMAwZMsQcMRIRERGZndFF0blz5zBy5EgAgKOjI+7fvw93d3fMnz8fH374ockDJCIiIrIEo4uiGjVqaMYR+fj44PLly5p1t27dMl1kRERERBZk9Jiibt264cCBAwgMDMSAAQPw1ltv4dSpU9iwYQO6detmjhiJiIiIzM7ooujTTz9FQUEBAGDevHkoKCjA999/jxYtWvDOMyIiIrJZRhVFSqUS165dQ1BQEAD1pTQ+xZqIiIjsgVFjihwcHBAREYGcnBxzxUNERERkFUYPtG7bti3+/vtvc8RCREREZDVGF0XvvfcepkyZgi1btiAzMxN5eXlaP0RERES2yOiB1gMGDAAADBw4EBKJRLNcCAGJRAKlUmm66IiIiIgshBPCEhEREaESRVFYWJg54iAiIiKyKqPHFBERERHZIxZFRERERGBRRERERATAykXRsmXLEBQUBE9PT3h6eiI0NBTbtm0rd5v169cjICAALi4uaNeuHbZu3WqhaImIiMieVbkoKi4u1syFZixfX1988MEHOHbsGFJSUvDUU08hKioKZ86c0dv+0KFDiImJwdixY3HixAlER0cjOjoap0+frkoKRERERMYVRWvWrMHrr7+OdevWAQBmzJgBDw8P1KxZE+Hh4bh9+7ZRO3/mmWcwYMAAtGjR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JCUlITw8HE5OTibtuzqw9/wA+8/R3vJLOZmDd94/q3nt7CQwflgeliV4olghgUQCNPJxwcpPQyCRlH2JxpbY2zFcvvYKNm29obkE+vAxlEqBqH4+eHXUY9YN1ETs7fjpY64cS670mFO1KIpKZiret2+f3pmKS/P29tY5I5SdnQ1vb2+97WUyGWQy3dPmTk5OZvtAmrPv6sDe8wPsP0d7ya9rSH34eNfAteuFWoN0ixUSFCvURdDQ6CZwdna2UoTmYy/HcNAAP/z0SxYeKAVKX7coOYaOjhIMGtDYLnItzV6OX3lMnaMl3i+rDrQWQmDChAnYuHEj9uzZU+ZMxaWFhoZi9+7dWsuSkpIQGhpqrjCJqJqSSiVYPLst6v//eKGSk0EODur/DhvsiwG9G1gpOjJEI29XvDejDRwd1WeFSkilgJOjBO9Nbw3fhpxqgyzDqmeKYmNjkZCQgJ9//lkzUzEA1KxZUzPfzMiRI9GoUSMsWrQIADBx4kSEhYXhk08+QWRkJBITE5GSkoKvvvrKankQkfU09HbF2i86Y9fem9h7KBtALsLDvPBMhC8CW5pn3AGZVo8udfHDiq7YvD0TqWduA8hFTLQvnunnZzcD5Mk2WLUoWrZsGQD1pH6lrVmzBqNHjwYApKena00E2L17dyQkJGDWrFmYOXMmWrRogU2bNqFt27aWCpuIqhlXFwc809cH/Z6qh61br+LNV1rY/aUJe1O/rgxjhzeBQtEIW7dew8ih/jyGZHFWLYoMufEtOTlZZ9mQIUMwZMgQM0REREREjyrOfUZEREQEFkVEREREAFgUEREREQFgUUREREQEgEUREREREQAWRUREREQAWBQRERERAWBRRERERASARRERERERABZFRERERABYFBEREREBYFFEREREBIBFEREREREAFkVEREREAFgUEREREQFgUUREREQEgEUREREREQAWRUREREQAWBQRERERAWBRRERERASARRERERERABZFRERERABYFBEREREBYFFEREREBIBFEREREREAFkVEREREAFgUEREREQFgUUREREQEgEUREREREQAWRUREREQAWBQRERERAbByUbRv3z4888wzaNiwISQSCTZt2lRu++TkZEgkEp2frKwsywRMREREdsuqRdG9e/fQvn17fPHFF0Ztd/78eWRmZmp+vLy8zBQhERERPSocrbnz/v37o3///kZv5+XlhVq1apk+ICIiInpkWbUoqqwOHTpALpejbdu2mDt3Lnr06FFmW7lcDrlcrnmdl5cHAFAoFFAoFCaNq6Q/U/dbXdh7foD958j8bJ+958j8bJ+5crTEeyYRQgiz78UAEokEGzduRHR0dJltzp8/j+TkZHTq1AlyuRwrV67E2rVrceTIEYSEhOjdZu7cuZg3b57O8oSEBLi5uZkqfCIiIjKjwsJCDBs2DLm5ufD09DTLPmyqKNInLCwMjRs3xtq1a/Wu13emyM/PD7du3TL5m6pQKJCUlITw8HA4OTmZtO/qwN7zA+w/R+Zn++w9R+Zn+8yVY15eHurVq2fWosgmL5+V1qVLFxw4cKDM9TKZDDKZTGe5k5OT2T6Q5uy7OrD3/AD7z5H52T57z5H52T5T52iJ98vmn1OUmpoKHx8fa4dBRERENs6qZ4oKCgpw6dIlzesrV64gNTUVderUQePGjTFjxgxcv34d33zzDQDgs88+Q9OmTdGmTRsUFRVh5cqV2LNnD3bu3GmtFIiIiMhOWLUoSklJQa9evTSvJ0+eDAAYNWoU4uPjkZmZifT0dM364uJivPXWW7h+/Trc3NwQFBSEXbt2afVBREREVBlWLYp69uyJ8sZ5x8fHa72eNm0apk2bZuaoiIiI6FFk82OKiIiIiEyBRRERERERWBQRERERAWBRRERERASARRERERERABZFRERERABYFBEREREBYFFEREREBIBFEREREREAFkVEREREAFgUEREREQFgUUREREQEgEUREREREQAWRUREREQAWBQRERERAWBRRERERASARRERERGZye3bt+Hl5YW0tDSL77tbt2746aefjNqGRRERERGZxcKFCxEVFYUmTZpolkkkEp2fxMREo/rdt28fnnnmGTRs2BASiQSbNm3SaTNr1ixMnz4dKpXK4H5ZFBEREZHJFRYWYtWqVRg7dqzOujVr1iAzM1PzEx0dbVTf9+7dQ/v27fHFF1+U2aZ///7Iz8/Htm3bDO7X0agoiIiIiAywbds2yGQydOvWTWddrVq14O3tXem++/fvj/79+5fbxsHBAQMGDEBiYiIiIyMN6pdnioiIiMjkDh48iI4dO+pdFxsbi3r16qFLly5YvXo1hBBmiaFLly7Yv3+/we15poiIiIhM7urVq2jYsKHO8vnz5+Opp56C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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.title(\"User Movie Preference\", size=15) \n",
    "plt.xlabel(\"Movie A rating\")\n",
    "plt.ylabel(\"Movie B rating\")\n",
    "plt.grid()\n",
    "\n",
    "# 绘制原始样本点，不同的影片喜好类别用不同的颜色标记\n",
    "plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', label=['动作片', '喜剧片'])\n",
    "\n",
    "# 绘制新数据点，用红色x标记，大小为80\n",
    "plt.plot(new_user[0, 0], new_user[0, 1], marker='x', color='red', markersize=8)\n",
    "\n",
    "# 获取新数据最近邻的距离和索引\n",
    "dist, idx = knn.kneighbors(new_user)\n",
    "nearest = X[idx[0][0]]  # 获取最近邻点的坐标\n",
    "\n",
    "# 用红线标记新数据点与最近邻点的连接线\n",
    "plt.plot(\n",
    "    [new_user[0, 0], nearest[0]], \n",
    "    [new_user[0, 1], nearest[1]], \n",
    "    'r--'  # 红色虚线\n",
    ")\n",
    "\n",
    "# 为每个点添加坐标文本  \n",
    "for x, y_coord in zip(X[:, 0], X[:, 1]):\n",
    "    plt.text(x, y_coord + 0.1, f'({x}, {y_coord})') \n",
    "\n",
    "# 为新数据点添加坐标文本\n",
    "plt.text(new_user[0,0], new_user[0,1] + 0.1, f'({new_user[0,0]}, {new_user[0,1]})')\n",
    "\n",
    "# 添加图例\n",
    "plt.legend(['新用户', '最近邻连接', '动作片', '喜剧片'])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
